package my.soft.aiteacher.aop;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import jakarta.annotation.Resource;
import my.soft.aiteacher.common.mapper.ViewsMapper;
import my.soft.aiteacher.student.pojo.Views;
import my.soft.aiteacher.student.service.IViewsService;
import my.soft.aiteacher.target.ViewCount;
import my.soft.aiteacher.teacher.mapper.FileUploadMapper;
import my.soft.aiteacher.teacher.pojo.FileUpload;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Aspect
@Component
public class ComprehensiveViewCountAspect {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private FileUploadMapper fileUploadMapper;

    @Resource
    private ViewsMapper viewsMapper;

    // 定义切点：所有带有@ViewCount注解的方法
    @Pointcut("@annotation(my.soft.aiteacher.target.ViewCount)")
    public void viewCountPointcut() {
    }


    @Around("viewCountPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法参数和注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ViewCount viewCount = method.getAnnotation(ViewCount.class);

        Object[] args = joinPoint.getArgs();
        Long id = (Long) args[0];

        String redisKey = String.format("video:view:%d", id);

        if (viewCount != null) {
            redisTemplate.opsForValue().increment(redisKey, 1);
        }

        return joinPoint.proceed();
    }

    //每十分钟从redis中查询并保存到数据库一次
    //corn表达式
    @Scheduled(cron = "0 0/10 * * * ?")
    public void saveViewCountsToDatabase() {

        Set<String> keys = redisTemplate.keys("video:view:*");
        if (keys == null || keys.isEmpty()) {
            return;
        }

        Map<Long, Long> videoIdCountMap = new HashMap<>();
        for (String key : keys) {

            Object o = redisTemplate.opsForValue().get(key);
            if (o != null) {
                Long count = Long.parseLong(o.toString());

                Long videoId = Long.parseLong(key.split(":")[2]);
                videoIdCountMap.put(videoId, count);
            }
        }
        if (videoIdCountMap.isEmpty()) {
            return;
        }
        //先存数据库后删redis
        List<Views> viewsList = videoIdCountMap.entrySet().stream()
                .map(entry -> new Views(entry.getKey(), entry.getValue()))
                .toList();
        //将原先数据累加
        List<Views> viewList = viewsMapper.selectList(new QueryWrapper<Views>().in("file_id", videoIdCountMap.keySet()));
        Map<Long, Views> viewsMap = viewList.stream().collect(Collectors.toMap(Views::getFileId, Function.identity()));
        for (Views views : viewsList) {
            views.setViews(views.getViews() + viewsMap.get(views.getFileId()).getViews());
            viewsMapper.update(new UpdateWrapper<Views>().set("views", views.getViews()).eq("file_id", views.getFileId()));
        }
        redisTemplate.delete(keys);

    }

    //删除file_upload表中不存在的views数据
    @Scheduled(cron = "0 0/10 * * * ?")
    public void deleteViews() {
        // 修改为使用 ArrayList 包装
        List<Long> fileIdList = new ArrayList<>(
                viewsMapper.selectList(new QueryWrapper<Views>().select("file_id"))
                        .stream()
                        .map(Views::getFileId)
                        .toList()
        );

        List<Long> fileIdList1 = new ArrayList<>(
                fileUploadMapper.selectList(new QueryWrapper<FileUpload>().select("id"))
                        .stream()
                        .map(FileUpload::getId)
                        .toList()
        );

        fileIdList.removeAll(fileIdList1);
        if (fileIdList.isEmpty()) {
            return;
        }
        viewsMapper.delete(new QueryWrapper<Views>().in("file_id", fileIdList));
    }

}